﻿using Tszy.Unlimited.Base.Collections;

namespace Tszy.Unlimited.Base.Infrastructure.Events;

/// <summary>
/// 事件管理器。
/// </summary>
public class EventManager
{
    private static readonly object _locker = new();
    private static EventManager _instance = new();

    private readonly MonoConcurrentDictionary<string, List<Action<object?, object>>> _actionListeners = new();
    private readonly MonoConcurrentDictionary<string, List<IEventListener>> _eventListeners = new();

    /// <summary>
    /// 唯一实例。
    /// </summary>
    public static EventManager Instance
    {
        get
        {
            if (_instance == null)
            {
                lock (_locker)
                {
                    if (_instance == null)
                    {
                        _instance = new EventManager();
                    }
                }
            }

            return _instance;
        }
    }

    /// <summary>
    /// 增加监听器。
    /// </summary>
    /// <typeparam name="TEvent">事件类型。</typeparam>
    /// <param name="callback">回调方法。</param>
    public void AddListener<TEvent>(Action<object?, object> callback)
    {
        if (callback == null)
            throw new ArgumentNullException(nameof(callback));

        var key = typeof(TEvent).ToString();

        if (_actionListeners.ContainsKey(key))
            _actionListeners[key]?.Add(callback);
        else
            _actionListeners.Add(key, new List<Action<object?, object>> { callback });
    }

    /// <summary>
    /// 增加监听器。
    /// </summary>
    /// <param name="eventListener">监听器。</param>
    public void AddListener(IEventListener eventListener)
    {
        if (eventListener == null)
            throw new ArgumentNullException(nameof(eventListener));

        var key = eventListener.EventType.ToString();

        if (_eventListeners.ContainsKey(key))
            _eventListeners[key]?.Add(eventListener);
        else
            _eventListeners.Add(key, new List<IEventListener> { eventListener });
    }

    /// <summary>
    /// 清空指定事件的监听器。
    /// </summary>
    public void ClearListener()
    {
        foreach (var listener in _actionListeners.Values)
            listener.Clear();

        foreach (var listener in _eventListeners.Values)
            listener.Clear();

        _actionListeners.Clear();
        _eventListeners.Clear();
    }

    /// <summary>
    /// 发布事件。
    /// </summary>
    /// <typeparam name="TEvent">事件类型。</typeparam>
    /// <param name="event">事件信息。</param>
    public void Publish<TEvent>(TEvent @event)
    {
        Publish(null, @event);
    }

    /// <summary>
    /// 发布事件。
    /// </summary>
    /// <typeparam name="TEvent">事件类型。</typeparam>
    /// <param name="sender">事件发送者。</param>
    /// <param name="event">事件信息。</param>
    public void Publish<TEvent>(object? sender, TEvent @event)
    {
        if (@event == null)
            throw new ArgumentNullException(nameof(@event));

        var key = @event.GetType().ToString();

        if (_actionListeners.ContainsKey(key))
        {
            var listeners = _actionListeners[key];

            if (listeners != null)
                foreach (var listener in listeners)
                    listener?.Invoke(sender, @event);
        }

        if (_eventListeners.ContainsKey(key))
        {
            var listeners = _eventListeners[key];

            if (listeners != null)
                foreach (var listener in listeners)
                {
                    if (listener != null)
                    {
                        listener.Listen(sender, @event);
                    }
                }
        }
    }
}
